﻿using OneByOne.API;
using System.Reflection;
using System.Text.Json;

namespace OneByOne
{
    internal class Game
    {
        private static IEnumerable<IPlugin> LoadPlugins(string pluginDirectory)
        {
            var dir = new DirectoryInfo(pluginDirectory);
            dir.Create();
            foreach (var file in dir.GetFiles("*.plugin"))
            {
                Console.WriteLine($"正在加载插件 {file.Name} ……");

                IPlugin result;
                try
                {
                    var assembly = Assembly.LoadFile(file.FullName);
                    var infoName = assembly.GetManifestResourceNames()
                        .Where(name => name.EndsWith("PluginInfo.json")).FirstOrDefault(string.Empty);
                    var info = assembly.GetManifestResourceStream(infoName);
                    if (info is null)
                    {
                        Console.WriteLine($"加载插件 {file.Name} 失败。已跳过。");
                        continue;
                    }
                    var pInfo = JsonSerializer.Deserialize<PluginInfoModel>(info);
                    if (pInfo is null || pInfo.Main is null)
                    {
                        Console.WriteLine($"加载插件 {file.Name} 失败。已跳过。");
                        continue;
                    }
                    var pType = assembly.GetType(pInfo.Main, false);
                    var constructor = pType?.GetConstructor(Array.Empty<Type>());
                    var plugin = constructor?.Invoke(null);
                    if (plugin is not IPlugin p)
                    {
                        Console.WriteLine($"加载插件 {file.Name} 失败。已跳过。");
                        continue;
                    }
                    result = p;
                }
                catch (Exception e)
                {
                    Console.WriteLine($"加载插件 {file.Name} 时产生了异常：");
                    Console.WriteLine(e);
                    Console.WriteLine($"已跳过插件 {file.Name} 的加载。");
                    continue;
                }

                yield return result;
            }
        }

        public Game()
        {
            Console.WriteLine("游戏初始化……");

            var pluginsPath = Path.Combine(AppContext.BaseDirectory, "plugins");
            this.plugins = LoadPlugins(pluginsPath).ToArray();
            this.player = new Player();
            this.enemies = new List<IEnemy>();

            Console.WriteLine("初始化完毕。");
        }

        private readonly IPlugin[] plugins;
        private sealed record GameSettings(Difficulty Difficulty) : IGameSettings;

        private static IEnumerable<IEnemy> GenerateEnemies(int difficulty)
        {
            Random r = new Random();
            foreach (var indexFactor in Enumerable.Range(1, difficulty * 3))
            {
                var randomFactor = r.Next(indexFactor * 2, indexFactor * 5);
                var strength = difficulty * indexFactor * randomFactor;
                yield return new Enemy()
                {
                    Name = $"第 {indexFactor} 个怪物",
                    Strength = strength,
                    Reward = (int)(strength * 1.2 / difficulty)
                };
            }
        }

        private int position;
        private readonly Player player;
        private readonly List<IEnemy> enemies;

        public void Run()
        {
            var difficultyInt =
                SystemConsole.ReadAndCheckPositiveInt("请选择难度 1-简单 2-普通 3-困难：");

            Console.WriteLine("加载中……");
            this.enemies.Clear();
            this.enemies.AddRange(GenerateEnemies(difficultyInt));
            this.player.Strength = this.enemies.FirstOrDefault(new Enemy()).Strength;
            foreach (var plugin in this.plugins)
                plugin.OnGameStart(new GameSettings((Difficulty)difficultyInt), this.player, this.enemies);
            Console.WriteLine("加载完毕。");

            var won = this.GameLoop();
            Console.WriteLine($"游戏结束！最终位于 {this.position} 处。");
            foreach (var plugin in this.plugins)
                plugin.OnGameOver(this.position, won);
        }

        private bool GameLoop()
        {
            this.position = 0;
            for (; ; )
            {
                var enemy = this.enemies[this.position];
                Console.WriteLine("===========One-By-One!===============================");
                Console.WriteLine($"你正位于 {this.position} 处，你前方的敌人为 {enemy.Name} 。");
                Console.WriteLine($"其战斗力 {enemy.Strength} ，当前你的战斗力为 {this.player.Strength} 。");
                var fight = SystemConsole.ReadAndCheckYesOrNo("要战斗吗？（y 战斗 n 后退）");
                if (fight)
                {
                    this.position++;

                    foreach (var plugin in this.plugins)
                        plugin.OnFighting(this.player, enemy);

                    if (this.player.Strength >= enemy.Strength)
                    {
                        Console.Write(
                            this.player.Strength == enemy.Strength ? "险胜！" : "你获胜了！");
                        this.player.Strength += enemy.Reward;
                        Console.WriteLine($"你获得了 {enemy.Reward} 点战斗力。当前战斗力 {this.player.Strength} 。");
                        if (this.position == this.enemies.Count)
                        {
                            Console.WriteLine("你击败了所有敌人！");
                            return true;
                        }
                    }
                    else
                    {
                        Console.WriteLine("你战败了！");
                        return false;
                    }
                }
                else
                {
                    this.position--;
                    if (this.position < 0)
                    {
                        Console.WriteLine("你掉下了悬崖！");
                        return false;
                    }
                }
            }
        }
    }
}